import { parse } from '@babel/parser';
import traverse from '@babel/traverse';
import * as t from '@babel/types';

interface ComplianceIssue {
  type: 'error' | 'warning';
  code: string;
  message: string;
  suggestion: string;
  line?: number;
  column?: number;
  codeSnippet?: string;
  snippetStartLine?: number;
  snippetEndLine?: number;
}

interface ComplianceResult {
  isCompliant: boolean;
  issues: ComplianceIssue[];
}

export class TSXComplianceChecker {
  /**
   * 使用 AST 检查 TSX 规范
   */
  static checkTSXCompliance(content: string, filename: string): ComplianceResult {
    const issues: ComplianceIssue[] = [];

    try {
      // 使用 Babel 解析 TSX 代码
      const ast = parse(content, {
        sourceType: 'module',
        plugins: ['jsx', 'typescript', 'decorators-legacy', 'classProperties'],
        errorRecovery: true,
      });

      // 遍历 AST 进行检查
      traverse(ast, {
        // 检查变量声明
        VariableDeclarator(path) {
          TSXComplianceChecker.checkVariableDeclaration(path, content, issues);
        },

        // 检查方法定义
        ClassMethod(path) {
          TSXComplianceChecker.checkMethodDefinition(path, content, issues);
        },

        // 检查 JSX 使用
        JSXElement(path) {
          TSXComplianceChecker.checkJSXUsage(path, content, issues);
        },

        // 检查类型注解
        TSTypeAnnotation(path) {
          TSXComplianceChecker.checkTypeAnnotation(path, content, issues);
        },
      });

      // 检查必需的结构
      this.checkRequiredStructures(ast, content, issues);
    } catch (error) {
      issues.push({
        type: 'error',
        code: 'PARSE_ERROR',
        message: `代码解析失败: ${error.message}`,
        suggestion: '检查代码语法是否正确',
      });
    }

    return {
      isCompliant: issues.filter((issue) => issue.type === 'error').length === 0,
      issues,
    };
  }

  /**
   * 检查变量声明
   */
  private static checkVariableDeclaration(path: any, content: string, issues: ComplianceIssue[]) {
    const node = path.node;

    // 检查是否在 render 方法中
    const renderMethod = path.findParent(
      (p: any) => p.isClassMethod() && t.isIdentifier(p.node.key) && p.node.key.name === 'render',
    );

    if (!renderMethod) return;

    // 检查是否在事件处理函数中
    const isInEventHandler = this.isInEventHandler(path);
    if (isInEventHandler) return;

    // 检查是否在非 JSX 返回的回调函数中
    const isInNonJSXCallback = this.isInNonJSXCallback(path);
    if (isInNonJSXCallback) return;

    // 检查是否在返回 JSX 的回调函数中（如 .map()）
    const isInJSXCallback = this.isInJSXCallback(path);
    if (isInJSXCallback) {
      // 这种情况需要报错
      const { line, column } = this.getLocation(path, content);
      const snippet = this.extractCodeSnippet(content, line);

      issues.push({
        type: 'error',
        code: 'CALLBACK_VARIABLE_DECLARATION',
        message: '返回 JSX 的回调函数中不能包含变量声明',
        suggestion: '将变量声明移到回调函数外部，或使用内联表达式',
        line,
        column,
        codeSnippet: snippet.snippet,
        snippetStartLine: snippet.startLine,
        snippetEndLine: snippet.endLine,
      });
      return;
    }

    // 其他在 render 方法中的变量声明都是错误的
    const { line, column } = this.getLocation(path, content);
    const snippet = this.extractCodeSnippet(content, line);

    issues.push({
      type: 'error',
      code: 'RENDER_VARIABLE_DECLARATION',
      message: 'render() 方法中不能包含变量声明',
      suggestion: '移除所有 const/let/var 声明，直接使用 this.state.xxx',
      line,
      column,
      codeSnippet: snippet.snippet,
      snippetStartLine: snippet.startLine,
      snippetEndLine: snippet.endLine,
    });
  }

  /**
   * 检查是否在事件处理函数中
   */
  private static isInEventHandler(path: any): boolean {
    // 查找父级 JSX 属性
    const jsxAttribute = path.findParent((p: any) => p.isJSXAttribute());
    if (jsxAttribute && t.isJSXIdentifier(jsxAttribute.node.name)) {
      const attrName = jsxAttribute.node.name.name;
      // 检查是否是事件处理属性（onXxx）
      if (/^on[A-Z]/.test(attrName)) {
        return true;
      }
    }

    // 检查是否在 addEventListener 回调中
    const callExpression = path.findParent((p: any) => p.isCallExpression());
    if (callExpression && t.isMemberExpression(callExpression.node.callee)) {
      const memberExpr = callExpression.node.callee;
      if (t.isIdentifier(memberExpr.property) && memberExpr.property.name === 'addEventListener') {
        return true;
      }
    }

    return false;
  }

  /**
   * 检查是否在非 JSX 返回的回调函数中
   */
  private static isInNonJSXCallback(path: any): boolean {
    // 查找父级函数
    const parentFunction = path.findParent(
      (p: any) => p.isArrowFunctionExpression() || p.isFunctionExpression(),
    );

    if (!parentFunction) return false;

    // 检查是否在 JSX 属性回调中（如 beforeUpload, customRequest 等）
    const jsxAttribute = parentFunction.findParent((p: any) => p.isJSXAttribute());
    if (jsxAttribute && t.isJSXIdentifier(jsxAttribute.node.name)) {
      const attrName = jsxAttribute.node.name.name;
      // 这些属性通常不返回 JSX
      const nonJSXAttributes = [
        'beforeUpload',
        'customRequest',
        'onChange',
        'onFinish',
        'onSubmit',
        'onSuccess',
        'onError',
        'onProgress',
        'request',
        'dataHandler',
      ];
      if (nonJSXAttributes.includes(attrName)) {
        return true;
      }
    }

    // 检查函数是否返回 JSX
    const returnsJSX = this.functionReturnsJSX(parentFunction);

    // 如果不返回 JSX，则认为是非 JSX 回调
    return !returnsJSX;
  }

  /**
   * 检查是否在返回 JSX 的回调函数中
   */
  private static isInJSXCallback(path: any): boolean {
    // 查找父级函数
    const parentFunction = path.findParent(
      (p: any) => p.isArrowFunctionExpression() || p.isFunctionExpression(),
    );

    if (!parentFunction) return false;

    // 检查函数是否返回 JSX
    return this.functionReturnsJSX(parentFunction);
  }

  /**
   * 检查函数是否返回 JSX
   */
  private static functionReturnsJSX(functionPath: any): boolean {
    let returnsJSX = false;

    functionPath.traverse({
      ReturnStatement(path: any) {
        if (path.node.argument && t.isJSXElement(path.node.argument)) {
          returnsJSX = true;
        }
      },
      JSXElement(path: any) {
        // 如果函数体直接包含 JSX（箭头函数的隐式返回）
        if (path.parent === functionPath.node.body) {
          returnsJSX = true;
        }
      },
    });

    return returnsJSX;
  }

  /**
   * 检查方法定义
   */
  private static checkMethodDefinition(path: any, content: string, issues: ComplianceIssue[]) {
    const node = path.node;

    // 跳过 render 方法和渲染相关方法
    if (t.isIdentifier(node.key)) {
      const methodName = node.key.name;
      const renderMethods = [
        'render',
        'renderItem',
        'renderContent',
        'renderHeader',
        'renderFooter',
      ];
      if (renderMethods.includes(methodName)) return;

      // 检查方法中是否包含 JSX
      let containsJSX = false;
      path.traverse({
        JSXElement() {
          containsJSX = true;
        },
      });

      if (containsJSX) {
        const { line, column } = this.getLocation(path, content);
        const snippet = this.extractCodeSnippet(content, line);

        issues.push({
          type: 'error',
          code: 'METHOD_CONTAINS_JSX',
          message: `方法 ${methodName} 不能包含 JSX 语法`,
          suggestion: '只有 render() 方法可以包含 JSX，其他方法只处理逻辑',
          line,
          column,
          codeSnippet: snippet.snippet,
          snippetStartLine: snippet.startLine,
          snippetEndLine: snippet.endLine,
        });
      }
    }
  }

  /**
   * 检查 JSX 使用
   */
  private static checkJSXUsage(path: any, content: string, issues: ComplianceIssue[]) {
    // 暂时不实现，专注于变量声明检查
  }

  /**
   * 检查类型注解
   */
  private static checkTypeAnnotation(path: any, content: string, issues: ComplianceIssue[]) {
    // 暂时不实现，专注于变量声明检查
  }

  /**
   * 检查必需的结构
   */
  private static checkRequiredStructures(ast: any, content: string, issues: ComplianceIssue[]) {
    // 这里可以添加对必需结构的检查
    // 如 IProps, IState, Document 类等
  }

  /**
   * 获取节点在源码中的位置
   */
  private static getLocation(path: any, content: string): { line: number; column: number } {
    const loc = path.node.loc;
    return {
      line: loc ? loc.start.line : 1,
      column: loc ? loc.start.column : 0,
    };
  }

  /**
   * 提取代码片段
   */
  private static extractCodeSnippet(
    content: string,
    lineNumber: number,
    contextLines: number = 3,
  ): { snippet: string; startLine: number; endLine: number } {
    const lines = content.split('\n');
    const startLine = Math.max(1, lineNumber - contextLines);
    const endLine = Math.min(lines.length, lineNumber + contextLines);

    const snippetLines = [];
    for (let i = startLine; i <= endLine; i++) {
      const line = lines[i - 1] || '';
      const prefix = i === lineNumber ? '>>> ' : '    ';
      snippetLines.push(`${prefix}${i.toString().padStart(3)}: ${line}`);
    }

    return {
      snippet: snippetLines.join('\n'),
      startLine,
      endLine,
    };
  }

  /**
   * 生成检查报告
   */
  static generateReport(result: ComplianceResult, filename: string): string {
    const { isCompliant, issues } = result;

    let report = '=== TSX 规范检查报告 ===\n';
    report += `文件: ${filename}\n`;

    if (isCompliant) {
      report += '✅ 检查通过：文件符合 TSX 规范\n';
    } else {
      const errorCount = issues.filter((issue) => issue.type === 'error').length;
      report += `❌ 检查失败：发现 ${errorCount} 个错误\n\n`;
      report += '--- 问题详情 ---\n';

      issues.forEach((issue, index) => {
        const icon = issue.type === 'error' ? '❌' : '⚠️';
        report += `${index + 1}. ${icon} [${issue.code}] ${issue.message}\n`;
        if (issue.line) {
          report += `   📍 位置: 第 ${issue.line} 行\n`;
        }
        report += `   💡 建议: ${issue.suggestion}\n`;
        if (issue.codeSnippet) {
          report += `   📝 代码片段:\n${issue.codeSnippet}\n`;
        }
        report += '\n';
      });
    }

    return report;
  }
}
